import socket
import threading
import logging
import os
import sys

if getattr(sys, 'frozen', False):  # 判断是否为 EXE 运行环境
    BASE_DIR = os.path.dirname(sys.executable)  # 获取 EXE 所在目录
else:
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # Python 运行环境
# 创建日志文件夹
log_folder = os.path.join(BASE_DIR, 'log')
os.makedirs(log_folder, exist_ok=True)
log_file = os.path.join(log_folder, 'server.log')  # 修改扩展名为 .log

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(log_file, encoding='utf-8'),
        logging.StreamHandler()
    ]
)

# 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 获取本地主机名和端口
host = socket.gethostname()
port = 9999

try:
    # 绑定端口号
    server_socket.bind((host, port))
    # 设置最大连接数
    server_socket.listen(5)
    logging.info(f"服务器已启动，正在监听 {host}:{port}")
except Exception as e:
    logging.error(f"服务器启动失败: {e}")
    server_socket.close()
    exit(1)

clients = []  # 存储所有连接的客户端
clients_lock = threading.Lock()  # 用于线程安全的客户端列表管理

def broadcast(message, sender_socket):
    """将消息广播给所有客户端"""
    with clients_lock:
        for client in clients:
            if client != sender_socket:  # 不发送给消息发送者
                try:
                    client.send(message)
                except Exception as e:
                    logging.warning(f"无法向客户端发送消息: {e}")
                    clients.remove(client)

def handle_client(client_socket):
    """处理单个客户端的消息"""
    addr = client_socket.getpeername()  # 获取客户端地址 (IP, Port)
    logging.info(f"客户端 {addr} 已连接")

    # 发送欢迎消息
    welcome_message = f"欢迎来到服务器！您的地址是 {addr}\n"
    try:
        client_socket.send(welcome_message.encode('utf-8'))
    except Exception as e:
        logging.error(f"无法向客户端 {addr} 发送欢迎消息: {e}")
        with clients_lock:
            clients.remove(client_socket)
        client_socket.close()
        return

    while True:
        try:
            message = client_socket.recv(1024)
            if not message:
                logging.info(f"客户端 {addr} 已断开连接")
                break
            # 在消息前附加发送者的端口号
            formatted_message = f"Port {addr[1]}: {message.decode('utf-8')}"
            logging.info(f"收到消息: {formatted_message}")
            broadcast(formatted_message.encode('utf-8'), client_socket)
        except Exception as e:
            logging.warning(f"客户端 {addr} 异常断开: {e}")
            break

    with clients_lock:
        if client_socket in clients:
            clients.remove(client_socket)  # 从客户端列表中移除
    client_socket.close()
    logging.info(f"客户端 {addr} 的连接已关闭")

try:
    while True:
        # 接受客户端连接
        client_socket, addr = server_socket.accept()
        logging.info(f"客户端 {addr} 正在尝试连接")
        with clients_lock:
            clients.append(client_socket)
        # 为每个客户端启动一个线程
        threading.Thread(target=handle_client, args=(client_socket,), daemon=True).start()
except KeyboardInterrupt:
    logging.info("服务器正在关闭...")
finally:
    with clients_lock:
        for client in clients:
            client.close()
    server_socket.close()
    logging.info("服务器已关闭")